﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FlexiCommerce.Components;
using FlexiCommerce.Persistence.NH;
using NUnit.Framework;
using Rhino.Mocks;
using FlexiCommerce.Engine;
using FlexiCommerce.Configuration;
using FlexiCommerce.Localization;

namespace FlexiCommerce.Tests.Persistence.NH
{
    [TestFixture]
    public class CategoryRepositoryTests : DatabasePreparingBase
    {
        NHRepository<int, Category> repository;
        ISessionProvider sessionProvider;

        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            CreateDatabaseSchema();

            sessionProvider = CreateSessionProvider();
            repository = new NHRepository<int, Category>(sessionProvider);
        }

        [Test]
        public void CanSave()
        {
            int itemID = SaveAnItem("savedItem", null);
            Assert.AreNotEqual(0, itemID);

            using (repository)
            {
                Category item = repository.Get<Category>(itemID);
                Assert.AreEqual(item.ID, itemID);
                repository.Delete(item);
                repository.Flush();
            }
        }

        [Test]
        public void CanUpdate()
        {
            int itemID = SaveAnItem("savedItem", null);

            using (repository)
            {
                Category item = repository.Get<Category>(itemID);
                item.Name = "updated item";
                repository.SaveOrUpdate(item);
                repository.Flush();
            }

            using (repository)
            {
                Category item = repository.Get<Category>(itemID);
                Assert.AreEqual("updated item", item.Name);
                repository.Delete(item);
                repository.Flush();
            }
        }

        [Test]
        public void CanFindAll()
        {
            int item1ID = SaveAnItem("first", null);
            int item2ID = SaveAnItem("second", null);
            int item3ID = SaveAnItem("third", null);

            using (repository)
            {
                ICollection<Category> items = repository.FindAll();
                Assert.AreEqual(3, items.Count);
                repository.Flush();
            }
        }

        [Test]
        public void CanDelete()
        {
            int itemID = SaveAnItem("k", null);

            using (repository)
            {
                Category item = repository.Get<Category>(itemID);
                Assert.IsNotNull(item, "There should be a saved item.");
                repository.Delete(item);
                repository.Flush();
            }

            using (repository)
            {
                Category item = repository.Get<Category>(itemID);
                Assert.IsNull(item, "Item is supposed to be deleted");
                repository.Flush();
            }
        }

        [Test]
        public void CanFindGreaterThanID()
        {
            int item1ID = SaveAnItem("first", null);
            int item2ID = SaveAnItem("second", null);
            int item3ID = SaveAnItem("third", null);

            using (repository)
            {
                ICollection<Category> items = repository.FindAll(NHibernate.Criterion.Expression.Gt("ID", 1));
                Assert.AreEqual(2, items.Count);
                repository.Flush();
            }
        }

        [Test]
        public void CanSaveDetail()
        {
            int item1ID = SaveAnItem("category 1", null);
            int item2ID = SaveAnItem("category 2", null);
            Culture lane = Culture.English;
            Culture lans = Culture.Spanish;

            Category cat = engine.Persister.Get<Category>(item1ID);
            Assert.AreEqual(0, cat.Details.Count);
            cat.AddDetail(new CategoryDetails("name", "description", lane));
            cat.AddDetail(new CategoryDetails("sname", "sdescription", lans));
            engine.Persister.Save(cat);
            cat = engine.Persister.Get<Category>(item1ID);
            Assert.AreEqual(2, cat.Details.Count);
            int details1ID = cat.Details[0].ID;
            int details2ID = cat.Details[1].ID;
            CategoryDetails detaile = Find.CategoryDetails.Where(d => d.Category == cat).Where(d => d.Culture == lane).SingleOrDefault();
            CategoryDetails details = Find.CategoryDetails.Where(d => d.Category == cat).Where(d => d.Culture == lans).SingleOrDefault();
            Assert.AreEqual(detaile.Culture, lane);
            Assert.AreEqual(details.Culture, lans);
            Assert.AreEqual(details.Category, cat);
            Assert.AreEqual(detaile.Category, cat);

            repository.Flush();

        }

        [Test]
        public void CanHaveProducts()
        {
            Category cat1 = engine.Persister.Get<Category>(SaveAnItem("first", null));
            Category cat2 = engine.Persister.Get<Category>(SaveAnItem("second", null));

            Product product1 = new Product();
            Product product2 = new Product();

            product1.Name = "Product 1";
            product1.Name = "Product 2";

            engine.Persister.Save(product1);
            engine.Persister.Save(product2);

            Assert.AreEqual(0, cat1.Products.Count);
            Assert.AreEqual(0, cat2.Products.Count);

            cat1.Products.Add(product1);

            cat2.Products.Add(product1);
            cat2.Products.Add(product2);

            engine.Persister.Save(cat1);
            engine.Persister.Save(cat2);

            cat1 = engine.Persister.Get<Category>(cat1.ID);
            cat2 = engine.Persister.Get<Category>(cat2.ID);

            Assert.AreEqual(1, cat1.Products.Count);
            EnumerableAssert.Contains(cat1.Products, product1);

            Assert.AreEqual(2, cat2.Products.Count);
            EnumerableAssert.Contains(cat2.Products, product1);
            EnumerableAssert.Contains(cat2.Products, product2);

        }

        private int SaveAnItem(string name, HierarchicalPersistenceItem parent)
        {
            try
            {

                    Category item = CreateOneItem<Category>(0, name, parent);
                    engine.Persister.Save(item);
                    engine.Persister.Flush();
                    return item.ID;

            }
            catch (Exception)
            {
                return 0;
            }


        }


    }
}
